package core;
/**
 * A class to manage Instructions and transform them between different representations:
 * 
 * 	- Assembly code (human readable)
 *  - Byte code (machine readable)
 *  - Class code (java readable)
 * @author Ximo Tur ximotur at gmail dot com
 */
public class InstructionClass {
	public short r_op1 = 0;
	public short r_op2 = 0;
	public short r_res = 0;
	public core.InstructionClass.InstructionType inst = null;
	public core.InstructionClass.ConditionalCodes cond = null;
	public boolean error = false;

	/**
	 * Creates a new instruction object using the given sentence as Assembly code.
	 * @param sentence is the assembly code to be read
	 */
	public InstructionClass(java.lang.String sentence){
		this.initInstruction(sentence);
	}
	/**
	 * Creates a new instruction from Byte code.
	 * If the instruction is one of format 4 (two words), the method setByteCode2(word) has to be callen
	 * @param word the Hex code for a Processor Instruction
	 */
	public InstructionClass(short word){
		this.initInstruction(word);
	}

	/**
	 * Returns a word that represents the code of the instruction
	 * @return returns the instruction in Hex representation
	 */
	public short getByteCode(){
		short res = 0;
		switch(this.inst.getFormat()){
			case 1:
				if(this.inst == core.InstructionClass.InstructionType.JR || this.inst == core.InstructionClass.InstructionType.CR){
					res = (short)(this.inst.getOpCode()<<10 | this.cond.getCondCode()<<6 | this.r_op1);
				}else{
					res = (short)((short)(this.inst.getOpCode())<<10 | this.r_op1<<6 | this.r_op2);
				}
				break;
			case 2:
				res = (short)(this.inst.getOpCode()<<10 | this.r_op1<<6);
				break;
			case 3:
				res = (short)(this.inst.getOpCode()<<10);
				break;
			case 4:
				if(this.inst == core.InstructionClass.InstructionType.J || this.inst == core.InstructionClass.InstructionType.C){
					res = (short)(this.inst.getOpCode()<<10 | this.cond.getCondCode()<<6);
				}else{
					res = (short)(this.inst.getOpCode()<<10 | this.r_op1<<6);
				}
				break;
		}
		return(res);
	}
	/**
	 * If the instruction is one of format = 4, returns the second word
	 * @return the OP2 of an instruction of format 4
	 */
	public short getByteCode2(){
		short res = 0;
		if(this.inst.getFormat() == 4){
			res = (short)r_op2;
		}
		return(res);
	}
	
	/**
	 * Sets the second word for an instruction of format 4
	 * @param word2 the second word to be set
	 */
	public void setByteCode2(short word2){
		if(this.inst.getFormat() == 4){
			this.r_op2 = word2;
		}
	}

	/**
	 * Generates the Assembly Code (readable assembly language) for this instruction
	 * @return the String representing the instruction
	 */
	public java.lang.String getAssembly(){
		java.lang.String res;
		switch(this.inst){
			case MOV:
			case SPB:
			case MLB:
			case MHB:
			case ADD:
			case ADC:
			case SUB:
			case SBC:
			case CMP:
			case AND:
			case OR:
			case XOR:
			case MVN:
			case BIC:
				res = this.inst.getStringCode() + " R" + this.r_op1 + ", R" + this.r_op2;
				break;
			case SHL:
			case SHR:
				res = java.lang.String.format("%s R%d, 0x%01X", this.inst.getStringCode(), this.r_op1, this.r_op2);
				break;
			case IMOV:
				res = this.inst.getStringCode() + " [R" + this.r_op1 + "], R" + this.r_op2;
				break;
			case MOVI:
				res = this.inst.getStringCode() + " R" + this.r_op1 + ", [R" + this.r_op2 + "]";
				break;
			case MMOV:
				res = java.lang.String.format("%s 0x%04X, R%d", this.inst.getStringCode(), this.r_op2, this.r_op1);
				break;
			case MOVM:
			case LDR:
			case ADDI:
			case ADCI:
			case SUBI:
			case SBCI:
			case CMPI:
			case ANDI:
			case ORI:
			case XORI:
			case BICI:
				res = java.lang.String.format("%s R%d, 0x%04X", this.inst.getStringCode(), this.r_op1, this.r_op2);
				break;
			case RET:
			case STOP:
			case NOP:
			case PUSHSR:
			case POPSR:
			case EI:
			case DI:
			case IRET:
			case SWI:
				res = this.inst.getStringCode();
				break;
			case MI:
			case UMI:
				res = this.inst.getStringCode() + " " + this.r_op1;
				break;
			case PUSH:
			case POP:
			case INC:
			case DEC:
				res = this.inst.getStringCode() + " R" + this.r_op1;
				break;
			case J:
			case C:
				res = java.lang.String.format("%s%s 0x%04X", this.inst.getStringCode(), this.cond.toString(), this.r_op2);
				break;
			case JR:
			case CR:
				res = this.inst.getStringCode() + this.cond.toString() + " [R" + this.r_op1 + "]";
				break;
			default:
				res = null;
				break;
		}
		return(res);
	}

	private void error(java.lang.String msg){
		System.err.println(msg);
		this.error = true;
		this.doNOP();
	}

	private void doNOP(){
		this.inst = core.InstructionClass.InstructionType.NOP;
	}
	
	private short decodeRegister(java.lang.String arg){
		int ret;
		if(this.isIndirect(arg)){
			//Erase the [] and R
			ret = java.lang.Integer.decode(arg.substring(2,arg.length()-1));
		}else if(this.isNorm(arg)){
			//Erase the first letter: R
			ret = java.lang.Integer.decode(arg.substring(1));
		}else{
			ret = java.lang.Integer.decode(arg);
		}
		return((short)ret);
	}

	private boolean isIndirect(java.lang.String arg){
		if(arg.startsWith("[") && arg.endsWith("]")){
			return(true);
		}else{
			return(false);
		}
	}
	private boolean isNorm(java.lang.String arg){
		return(arg.startsWith("R"));
	}
/*
	private boolean isInmediate(java.lang.String arg){
		return(arg.startsWith("0x") || !arg.matches("\\d"));
	}
*/
	/**
	 * Parses a string for an instruction
	 * @param sentence
	 */
	private void initInstruction(java.lang.String sentence){
		sentence = sentence.trim();
		java.lang.String toks[] = sentence.split(" ");
		if(toks.length == 1){
			//No args sentences:
			if(toks[0].compareTo("RET")==0){
				this.inst = core.InstructionClass.InstructionType.RET;
			}else if(toks[0].compareTo("PUSHSR")==0){
				this.inst = core.InstructionClass.InstructionType.PUSHSR;
			}else if(toks[0].compareTo("POPSR")==0){
				this.inst = core.InstructionClass.InstructionType.POPSR;
			}else if(toks[0].compareTo("NOP")==0){
				this.inst = core.InstructionClass.InstructionType.NOP;
			}else if(toks[0].compareTo("STOP")==0){
				this.inst = core.InstructionClass.InstructionType.STOP;
			}else if(toks[0].compareTo("EI")==0){
				this.inst = core.InstructionClass.InstructionType.EI;
			}else if(toks[0].compareTo("DI")==0){
				this.inst = core.InstructionClass.InstructionType.DI;
			}else if(toks[0].compareTo("IRET")==0){
				this.inst = core.InstructionClass.InstructionType.IRET;
			}else if(toks[0].compareTo("SWI")==0){
				this.inst = core.InstructionClass.InstructionType.SWI;
			}else{
				this.error("Ilegal Instruction " + sentence);
			}
		}else{
			java.lang.String arg = "";
			for(int i=1; i<toks.length; i++){
				arg = arg.concat(toks[i]);
			}
			java.lang.String[] args = arg.split(",");
			switch(args.length){
			case 1:
				try{
					boolean ind1 = this.isIndirect(args[0]);
					boolean norm1 = this.isNorm(args[0]);
					boolean inm1 = !norm1 && !ind1;
					//OP1 does NOT save any immediate data or memory address.
					if(norm1 || ind1){
						this.r_res = this.r_op1 = this.decodeRegister(args[0]);
					}else{
						this.r_op2 = this.decodeRegister(args[0]);
					}
					if(toks[0].compareTo("INC")==0){
						this.inst = core.InstructionClass.InstructionType.INC;
					}else if(toks[0].compareTo("DEC")==0){
						this.inst = core.InstructionClass.InstructionType.DEC;
					}else if(toks[0].compareTo("PUSH")==0){
						this.inst = core.InstructionClass.InstructionType.PUSH;
					}else if(toks[0].compareTo("POP")==0){
						this.inst = core.InstructionClass.InstructionType.POP;
					}else if(toks[0].compareTo("MI")==0){
						if(inm1 && (this.r_op2<4 && this.r_op2>0)){
							this.inst = core.InstructionClass.InstructionType.MI;
							this.r_op1 = this.r_op2;
						}else{
							this.error("Illegal argument");
						}
					}else if(toks[0].compareTo("UMI")==0){
						if(inm1 && (this.r_op2<4 && this.r_op2>0)){
							this.inst = core.InstructionClass.InstructionType.UMI;
							this.r_op1 = this.r_op2;
						}else{
							this.error("Illegal argument");
						}
					}else if(toks[0].startsWith("J") || toks[0].startsWith("C")){
						if(toks[0].startsWith("J")){
							if(ind1){
								this.inst = core.InstructionClass.InstructionType.JR;
							}else if(inm1){
								this.inst = core.InstructionClass.InstructionType.J;
							}else{
								this.error("Illegal Argument (jump)");
							}
						}else if(toks[0].startsWith("C")){
							if(ind1){
								this.inst = core.InstructionClass.InstructionType.CR;
							}else if(inm1){
								this.inst = core.InstructionClass.InstructionType.C;
							}else{
								this.error("Ilegal Argument");
							}
						}else{
							this.doNOP();
						}
						if(toks[0].endsWith("AL")){
							this.cond = core.InstructionClass.ConditionalCodes.AL;
						}else if(toks[0].endsWith("EQ")){
							this.cond = core.InstructionClass.ConditionalCodes.EQ;
						}else if(toks[0].endsWith("NE")){
							this.cond = core.InstructionClass.ConditionalCodes.NE;
						}else if(toks[0].endsWith("CS")){
							this.cond = core.InstructionClass.ConditionalCodes.CS;
						}else if(toks[0].endsWith("CC")){
							this.cond = core.InstructionClass.ConditionalCodes.CC;
						}else if(toks[0].endsWith("PL")){
							this.cond = core.InstructionClass.ConditionalCodes.PL;
						}else if(toks[0].endsWith("MI")){
							this.cond = core.InstructionClass.ConditionalCodes.MI;
						}else if(toks[0].endsWith("HI")){
							this.cond = core.InstructionClass.ConditionalCodes.HI;
						}else if(toks[0].endsWith("LS")){
							this.cond = core.InstructionClass.ConditionalCodes.LS;
						}else if(toks[0].endsWith("GE")){
							this.cond = core.InstructionClass.ConditionalCodes.GE;
						}else if(toks[0].endsWith("GT")){
							this.cond = core.InstructionClass.ConditionalCodes.GT;
						}else if(toks[0].endsWith("LE")){
							this.cond = core.InstructionClass.ConditionalCodes.LE;
						}else if(toks[0].endsWith("LT")){
							this.cond = core.InstructionClass.ConditionalCodes.LT;
						}else{
							this.error("Ilegal Condition");
						}
					}else{
						this.error("Ilegal Instruction");
					}
				}catch(java.lang.NumberFormatException e){
					e.printStackTrace();
					this.error("Second argument has to be an integer (1 arg)");
				}
				break;
			case 2:
				try{
					boolean ind1 = this.isIndirect(args[0]);
					boolean norm1 = this.isNorm(args[0]);
					boolean inm1 = !norm1 && !ind1;
					boolean ind2 = this.isIndirect(args[1]);
					boolean norm2 = this.isNorm(args[1]);
					boolean inm2 = !norm2 && !ind2;
					//OP1 does NOT save any immediate data or memory address.
					if(norm1 || ind1){
						this.r_res = this.r_op1 = this.decodeRegister(args[0]);
						this.r_op2 = this.decodeRegister(args[1]);
					}else{
						this.r_res = this.r_op1 = this.decodeRegister(args[1]);
						this.r_op2 = this.decodeRegister(args[0]);
					}
					if(toks[0].compareTo("MOV") == 0){
						if(ind1 && norm2){
							this.inst = core.InstructionClass.InstructionType.IMOV;
						}else if(ind2 && norm1){
							this.inst = core.InstructionClass.InstructionType.MOVI;
						}else if(inm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.MMOV;
						}else if(inm2 && norm1){
							this.inst = core.InstructionClass.InstructionType.MOVM;
						}else if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.MOV;
						}
					}else if(toks[0].compareTo("LDR")==0){
						if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.LDR;
						}
					}else if(toks[0].compareTo("SPB")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.SPB;
						}
					}else if(toks[0].compareTo("MLB")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.MLB;
						}
					}else if(toks[0].compareTo("MHB")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.MHB;
						}
					}else if(toks[0].compareTo("MVN")==0){
						if(norm1 & norm2){
							this.inst = core.InstructionClass.InstructionType.MVN;
						}
					}else if(toks[0].compareTo("ADD")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.ADD;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.ADDI;
						}
					}else if(toks[0].compareTo("ADC")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.ADC;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.ADCI;
						}
					}else if(toks[0].compareTo("SUB")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.SUB;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.SUBI;
						}
					}else if(toks[0].compareTo("SBC")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.SBC;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.SBCI;
						}
					}else if(toks[0].compareTo("CMP")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.CMP;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.CMPI;
						}
					}else if(toks[0].compareTo("AND")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.AND;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.ANDI;
						}
					}else if(toks[0].compareTo("OR")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.OR;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.ORI;
						}
					}else if(toks[0].compareTo("XOR")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.XOR;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.XORI;
						}
					}else if(toks[0].compareTo("BIC")==0){
						if(norm1 && norm2){
							this.inst = core.InstructionClass.InstructionType.BIC;
						}else if(norm1 && inm2){
							this.inst = core.InstructionClass.InstructionType.BICI;
						}
					}else if(toks[0].compareTo("SHL")==0){
						if(norm1 && inm2 && ((this.r_op2 & 0xFFF0) == 0)){
							this.inst = core.InstructionClass.InstructionType.SHL;
						}
					}else if(toks[0].compareTo("SHR")==0){
						if(norm1 && inm2 && ((this.r_op2 & 0xFFF0) == 0)){
							this.inst = core.InstructionClass.InstructionType.SHR;
						}
					}else{
						this.error("Illegal Instruction");
					}
					if(this.inst == null){
						this.error("Illegal arguments");
					}
				}catch(java.lang.NumberFormatException e){
					this.error("Second argument has to be an integer (2 args)");
				}
				break;
			default:
				this.doNOP();
				break;
			}
		}
	}

	/**
	 * Creates the instruction from the ByteCode
	 * @param the word
	 */
	private void initInstruction(short inst){
		short opCode = (short)((inst>>10) & 0x003F);
		this.r_op1 = this.r_res =  (short)((inst & 0x03C0)>>6);
		this.r_op2 = (short)(inst & 0x000F);
		switch(opCode){
			case 38:
				this.inst = core.InstructionClass.InstructionType.MOV;
				break;
			case 1:
				this.inst = core.InstructionClass.InstructionType.MOVI;
				break;
			case 2:
				this.inst = core.InstructionClass.InstructionType.IMOV;
				break;
			case 3:
				this.inst = core.InstructionClass.InstructionType.MOVM;
				break;
			case 4:
				this.inst = core.InstructionClass.InstructionType.MMOV;
				break;
			case 5:
				this.inst = core.InstructionClass.InstructionType.LDR;
				break;
			case 6:
				this.inst = core.InstructionClass.InstructionType.SPB;
				break;
			case 7:
				this.inst = core.InstructionClass.InstructionType.MLB;
				break;
			case 8:
				this.inst = core.InstructionClass.InstructionType.MHB;
				break;
			case 9:
				this.inst = core.InstructionClass.InstructionType.ADD;
				break;
			case 10:
				this.inst = core.InstructionClass.InstructionType.ADDI;
				break;
			case 11:
				this.inst = core.InstructionClass.InstructionType.ADC;
				break;
			case 12:
				this.inst = core.InstructionClass.InstructionType.ADCI;
				break;
			case 13:
				this.inst = core.InstructionClass.InstructionType.SUB;
				break;
			case 14:
				this.inst = core.InstructionClass.InstructionType.SUBI;
				break;
			case 15:
				this.inst = core.InstructionClass.InstructionType.SBC;
				break;
			case 16:
				this.inst = core.InstructionClass.InstructionType.SBCI;
				break;
			case 17:
				this.inst = core.InstructionClass.InstructionType.INC;
				break;
			case 18:
				this.inst = core.InstructionClass.InstructionType.DEC;
				break;
			case 19:
				this.inst = core.InstructionClass.InstructionType.CMP;
				break;
			case 20:
				this.inst = core.InstructionClass.InstructionType.CMPI;
				break;
			case 21:
				this.inst = core.InstructionClass.InstructionType.AND;
				break;
			case 22:
				this.inst = core.InstructionClass.InstructionType.ANDI;
				break;
			case 23:
				this.inst = core.InstructionClass.InstructionType.OR;
				break;
			case 24:
				this.inst = core.InstructionClass.InstructionType.ORI;
				break;
			case 25:
				this.inst = core.InstructionClass.InstructionType.XOR;
				break;
			case 26:
				this.inst = core.InstructionClass.InstructionType.XORI;
				break;
			case 27:
				this.inst = core.InstructionClass.InstructionType.SHL;
				break;
			case 28:
				this.inst = core.InstructionClass.InstructionType.SHR;
				break;
			case 29:
				this.inst = core.InstructionClass.InstructionType.J;
				break;
			case 30:
				this.inst = core.InstructionClass.InstructionType.JR;
				break;
			case 31:
				this.inst = core.InstructionClass.InstructionType.C;
				break;
			case 32:
				this.inst = core.InstructionClass.InstructionType.CR;
				break;
			case 33:
				this.inst = core.InstructionClass.InstructionType.RET;
				break;
			case 34:
				this.inst = core.InstructionClass.InstructionType.PUSH;
				break;
			case 35:
				this.inst = core.InstructionClass.InstructionType.POP;
				break;
			case 36:
				this.inst = core.InstructionClass.InstructionType.PUSHSR;
				break;
			case 37:
				this.inst = core.InstructionClass.InstructionType.POPSR;
				break;
			case 39:
				this.inst = core.InstructionClass.InstructionType.NOP;
				break;
			case 40:
				this.inst = core.InstructionClass.InstructionType.MVN;
				break;
			case 41:
				this.inst = core.InstructionClass.InstructionType.BIC;
				break;
			case 42:
				this.inst = core.InstructionClass.InstructionType.BICI;
				break;
			case 43:
				this.inst = core.InstructionClass.InstructionType.EI;
				break;
			case 44:
				this.inst = core.InstructionClass.InstructionType.DI;
				break;
			case 45:
				this.inst = core.InstructionClass.InstructionType.MI;
				break;
			case 46:
				this.inst = core.InstructionClass.InstructionType.UMI;
				break;
			case 47:
				this.inst = core.InstructionClass.InstructionType.IRET;
				break;
			case 48:
				this.inst = core.InstructionClass.InstructionType.SWI;
				break;
			case 0:
			default:
				this.inst = core.InstructionClass.InstructionType.STOP;
				break;
		}
		//Deal with Conditional instructions that has a condition.
		if(opCode == 29 || opCode == 30 || opCode == 31 || opCode == 32){
			switch(this.r_op1){
				case 0:
					this.cond = core.InstructionClass.ConditionalCodes.AL;
					break;
				case 1:
					this.cond = core.InstructionClass.ConditionalCodes.EQ;
					break;
				case 2:
					this.cond = core.InstructionClass.ConditionalCodes.NE;
					break;
				case 3:
					this.cond = core.InstructionClass.ConditionalCodes.CS;
					break;
				case 4:
					this.cond = core.InstructionClass.ConditionalCodes.CC;
					break;
				case 5:
					this.cond = core.InstructionClass.ConditionalCodes.PL;
					break;
				case 6:
					this.cond = core.InstructionClass.ConditionalCodes.MI;
					break;
				case 7:
					this.cond = core.InstructionClass.ConditionalCodes.HI;
					break;
				case 8:
					this.cond = core.InstructionClass.ConditionalCodes.LS;
					break;
				case 9:
					this.cond = core.InstructionClass.ConditionalCodes.GE;
					break;
				case 10:
					this.cond = core.InstructionClass.ConditionalCodes.GT;
					break;
				case 11:
					this.cond = core.InstructionClass.ConditionalCodes.LE;
					break;
				case 12:
				default:
					this.cond = core.InstructionClass.ConditionalCodes.LT;
					break;
			}
			this.r_op1 = this.r_res = this.r_op2;
		}
	}

	public enum InstructionType{
		MOV (38,1, core.InstructionClass.GuiEditorInstruction.MOV),
		MOVI (1,1,"MOV", core.InstructionClass.GuiEditorInstruction.MOV),
		IMOV (2,1,"MOV", core.InstructionClass.GuiEditorInstruction.MOV),
		MOVM (3,4,"MOV", core.InstructionClass.GuiEditorInstruction.MOV),
		MMOV (4,4,"MOV", core.InstructionClass.GuiEditorInstruction.MOV),
		MVN (40, 1, core.AluClass.Operations.NOT, core.InstructionClass.GuiEditorInstruction.MVN),
		LDR (5,4, core.InstructionClass.GuiEditorInstruction.LDR),
		SPB (6,1, core.InstructionClass.GuiEditorInstruction.SPB),
		MLB (7,1, core.InstructionClass.GuiEditorInstruction.MLB),
		MHB (8,1, core.InstructionClass.GuiEditorInstruction.MHB),
		ADD (9,1, core.AluClass.Operations.ADD, core.InstructionClass.GuiEditorInstruction.ADD),
		ADDI (10,4,"ADD", core.AluClass.Operations.ADD, core.InstructionClass.GuiEditorInstruction.ADD),
		ADC (11,1, core.AluClass.Operations.ADC, core.InstructionClass.GuiEditorInstruction.ADC),
		ADCI (12,4,"ADC", core.AluClass.Operations.ADC, core.InstructionClass.GuiEditorInstruction.ADC),
		SUB (13,1, core.AluClass.Operations.SUB, core.InstructionClass.GuiEditorInstruction.SUB),
		SUBI (14,4,"SUB", core.AluClass.Operations.SUB, core.InstructionClass.GuiEditorInstruction.SUB),
		SBC (15,1, core.AluClass.Operations.SBC, core.InstructionClass.GuiEditorInstruction.SBC),
		SBCI (16,4,"SBC", core.AluClass.Operations.SBC, core.InstructionClass.GuiEditorInstruction.SBC),
		INC (17,2, core.AluClass.Operations.ADD, core.InstructionClass.GuiEditorInstruction.INC),
		DEC (18,2, core.AluClass.Operations.SUB, core.InstructionClass.GuiEditorInstruction.DEC),
		CMP (19,1, core.AluClass.Operations.CMP, core.InstructionClass.GuiEditorInstruction.CMP),
		CMPI (20,4,"CMP", core.AluClass.Operations.CMP, core.InstructionClass.GuiEditorInstruction.CMP),
		AND (21,1, core.AluClass.Operations.AND, core.InstructionClass.GuiEditorInstruction.AND),
		ANDI (22,4,"AND", core.AluClass.Operations.AND, core.InstructionClass.GuiEditorInstruction.AND),
		OR (23,1, core.AluClass.Operations.OR, core.InstructionClass.GuiEditorInstruction.OR),
		ORI (24,4,"OR", core.AluClass.Operations.OR, core.InstructionClass.GuiEditorInstruction.OR),
		XOR (25,1, core.AluClass.Operations.XOR, core.InstructionClass.GuiEditorInstruction.XOR),
		XORI (26,4,"XOR", core.AluClass.Operations.XOR, core.InstructionClass.GuiEditorInstruction.XOR),
		SHL (27,1, core.AluClass.Operations.SHL, core.InstructionClass.GuiEditorInstruction.SHL),
		SHR (28,1, core.AluClass.Operations.SHR, core.InstructionClass.GuiEditorInstruction.SHR),
		BIC (41, 1, core.AluClass.Operations.BIC, core.InstructionClass.GuiEditorInstruction.BIC),
		BICI (42, 4, "BIC", core.AluClass.Operations.BIC, core.InstructionClass.GuiEditorInstruction.BIC),
		J (29,4, core.InstructionClass.GuiEditorInstruction.J),
		JR (30,1, "J", core.InstructionClass.GuiEditorInstruction.J),
		C (31,4, core.InstructionClass.GuiEditorInstruction.C),
		CR (32,1, "C", core.InstructionClass.GuiEditorInstruction.C),
		RET (33,3, core.InstructionClass.GuiEditorInstruction.RET),
		PUSH (34,2, core.InstructionClass.GuiEditorInstruction.PUSH),
		POP (35,2, core.InstructionClass.GuiEditorInstruction.POP),
		PUSHSR (36,3, core.InstructionClass.GuiEditorInstruction.PUSHSR),
		POPSR (37,3, core.InstructionClass.GuiEditorInstruction.POPSR),
		NOP (39,3, core.InstructionClass.GuiEditorInstruction.NOP),
		STOP (0,3, core.InstructionClass.GuiEditorInstruction.STOP),
		EI(43, 3, core.InstructionClass.GuiEditorInstruction.EI),
		DI(44, 3, core.InstructionClass.GuiEditorInstruction.DI),
		MI(45, 2, core.InstructionClass.GuiEditorInstruction.MI),
		UMI(46, 2, core.InstructionClass.GuiEditorInstruction.UMI),
		IRET(47, 3, core.InstructionClass.GuiEditorInstruction.IRET),
		SWI(48, 3, core.InstructionClass.GuiEditorInstruction.SWI);
		
		private byte opCode;
		private java.lang.String origCod;
		private byte format;
		private core.AluClass.Operations a_op;
		private core.InstructionClass.GuiEditorInstruction guiEditorInstruction;

		InstructionType(int cod, int format, core.InstructionClass.GuiEditorInstruction f){
			this.opCode = (byte)cod;
			this.format = (byte)format;
			this.origCod = this.toString();
			this.guiEditorInstruction = f;
		}
		InstructionType(int cod, int format, core.AluClass.Operations a_op, core.InstructionClass.GuiEditorInstruction f){
			this.opCode = (byte)cod;
			this.format = (byte)format;
			this.a_op = a_op;
			this.origCod = this.toString();
			this.guiEditorInstruction = f;
		}
		InstructionType(int cod, int format, java.lang.String origCod, core.InstructionClass.GuiEditorInstruction f){
			this.opCode = (byte)cod;
			this.format = (byte)format;
			this.origCod = origCod;
			this.guiEditorInstruction = f;
		}
		InstructionType(int cod, int format, java.lang.String origCod, core.AluClass.Operations a_op, core.InstructionClass.GuiEditorInstruction f){
			this.opCode = (byte)cod;
			this.format = (byte)format;
			this.a_op = a_op;
			this.origCod = origCod;
			this.guiEditorInstruction = f;
		}
		public byte getOpCode(){
			return(this.opCode);
		}
		public byte getFormat(){
			return(this.format);
		}		
		public core.AluClass.Operations getAluOperation(){
			return(this.a_op);
		}
		public java.lang.String getStringCode(){
			return(this.origCod);
		}
		public core.InstructionClass.GuiEditorInstruction getGuiInstruction(){
			return(this.guiEditorInstruction);
		}
	}
	public enum ConditionalCodes{
		AL(0, "AL"),
		EQ(1, "EQ"),
		NE(2, "NE"),
		CS(3, "CS/HS"),
		CC(4, "CC/LO"),
		PL(5, "PL"),
		MI(6, "MI"),
		HI(7, "HI"),
		LS(8, "LS"),
		GE(9, "GE"),
		GT(10, "GT"),
		LE(11, "LE"),
		LT(12, "LT");
		private byte condCode;
		//private java.lang.String name;
		ConditionalCodes(int cod, java.lang.String name){
			this.condCode = (byte)cod;
			//this.name = name;
		}
/*		public java.lang.String toString(){
			return(this.name);
		}*/
		public byte getCondCode(){
			return(this.condCode);
		}
	}
	public enum InstructionFormat{
		F1,
		F2,
		F3,
		F4
	}
	public enum InstructionSets{
		DATA,
		ARITMETIC,
		LOGIC,
		CONTROL
	}
	public enum GuiEditorInstruction{
		ADC (4),
		ADD (4),
		AND (4),
		BIC (4),
		C (5),
		CMP (4),
		DEC (1),
		DI (0),
		EI (0),
		INC (1),
		IRET(0),
		J (5),
		LDR (2),
		MHB (3),
		MI (7),
		MLB (3),
		MOV (6),
		MVN (3),
		NOP (0),
		OR (4),
		PUSH (1),
		PUSHSR (0),
		POP (1),
		POPSR (0),
		RET (0),
		SBC (4),
		SHL (2),
		SHR (2),
		SPB (3),
		STOP (0),
		SUB (4),
		SWI (0),
		UMI (7),
		XOR (4);
		/*
		 * CODES:
		 * 	0: No args
		 *  1: Register
		 *  2: Register + Immediate
		 *  3: Register + Register
		 *  4: ADD (ADDI), OR (ORI)... with 2 args
		 *  5: Jump and Call
		 *  6: MOV
		 *  7: Immediate
		 */
		private int guiCod = 0;

		GuiEditorInstruction(int cod){
			this.guiCod = cod;
		}

		public int getCod(){
			return(this.guiCod);
		}
	}
}
